﻿using System;
using System.Collections.Generic;
using AutoMapper;
using Budget.Core.Data;
using Budget.Core.DomainModel;
using Budget.Core.Extensions;
using Budget.Core.Specifications;
using Budget.Wcf.Core.Dto;
using Budget.Wcf.Core.Interfaces;
using Castle.Core.Logging;

namespace Budget.Wcf.Services
{
    public class OutcomeService : BaseService, IOutcomeService
    {
        private readonly IRepository<Category> categoryRepo;
        private readonly IRepository<Product> productRepo;
        private readonly IRepository<OutcomeOrder> orderRepo;
        private readonly IRepository<Balance> balanceRepo;

        public OutcomeService(ILogger logger, IRepository<Category> categoryRepo, IRepository<Product> productRepo, IRepository<OutcomeOrder> orderRepo, IRepository<Balance> balanceRepo)
            : base(logger)
        {
            this.categoryRepo = categoryRepo;
            this.productRepo = productRepo;
            this.orderRepo = orderRepo;
            this.balanceRepo = balanceRepo;
        }

        public IList<CategoryData> GetAllCategories()
        {
            try
            {
                var dbCategories = categoryRepo.Find.All();
                var dataCategories = Mapper.Map<IList<Category>, IList<CategoryData>>(dbCategories);
                return dataCategories;
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
                return null;
            }

        }

        public OutcomeOrderResult AddOutcomeOrder(OutcomeOrderData outcomeOrder)
        {
            try
            {
                var lastBalance = balanceRepo.Find.One(BalanceSpecifications.Latest());
                var product = Mapper.Map<Product>(outcomeOrder.Product);
                var dbOrder = lastBalance != null
                                  ? new OutcomeOrder(lastBalance, product)
                                  : new OutcomeOrder(product);
                dbOrder.Amount = outcomeOrder.Amount;
                dbOrder.CreationDate = outcomeOrder.CreationDate;
                orderRepo.SaveOrUpdate(dbOrder);
                return new OutcomeOrderResult
                    {
                        CategoryId = dbOrder.Product.Category.Id,
                        ProductId = dbOrder.Product.Id,
                        OutcomeOrderId = dbOrder.Id
                    };
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
                return new OutcomeOrderResult();
            }
        }

        public IList<OutcomeOrderData> GetOutcomeOrdersByDate(DateTime date)
        {
            try
            {
                var dbOrders = orderRepo.Find.All(OutcomeSpecifications.ByDate(date.Date));
                return Mapper.Map<IList<OutcomeOrderData>>(dbOrders);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
                return null;
            }
        }

        public IList<OutcomeOrderData> GetMonthOutcomes(int year, int month)
        {
            try
            {
                var daysCount = DateTime.DaysInMonth(year, month);
                var outcomes = orderRepo.Find.All(OutcomeSpecifications.Range(new DateTime(year, month, 1), new DateTime(year, month, daysCount)));
                return Mapper.Map<IList<OutcomeOrderData>>(outcomes);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details);

                return null;
            }
        }

        public void UpdateCategory(CategoryData categoryData)
        {
            try
            {
                var category = Mapper.Map<Category>(categoryData);
                categoryRepo.SaveOrUpdate(category);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
            }
        }

        public void UpdateProduct(ProductData productData)
        {
            try
            {
                var product = Mapper.Map<Product>(productData);
                productRepo.SaveOrUpdate(product);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
            }
        }

        public void DeleteOutcomeOrder(OutcomeOrderData outcomeOrderData)
        {
            try
            {
                var outcomeOrder = Mapper.Map<OutcomeOrder>(outcomeOrderData);
                orderRepo.Remove(outcomeOrder);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
            }
        }

        public void UpdateOutcomeOrder(OutcomeOrderData outcomeOrderData)
        {
            try
            {
                var order = Mapper.Map<OutcomeOrder>(outcomeOrderData);
                orderRepo.SaveOrUpdate(order);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Details());
            }
        }
    }
}